/*
puppeteer常用方法的封装，也可以借鉴
 */
const assert = require('assert');
const puppeteer = require('puppeteer'); //引入puppeteer库

/**
 * 获取指定元素的 BoundingClient   {
            x,
            y,
            width,
            height
        }
 * @param page
 * @param className  css选择语法
 * @returns {Promise<void>}   {
            x,
            y,
            width,
            height
        }
 */
async function getBoundingClientRect(page, className) {
    return await page.$eval(className, (classNameElement) => {
        let {
            x,
            y,
            width,
            height
        } = classNameElement.getBoundingClientRect();
        return {
            x,
            y,
            width,
            height
        };
    });
}

async function getResourceTree(page) {
    var resource = await page._client.send('Page.getResourceTree');
    return resource.frameTree;
}


/**
 * 获取指定url的资源
 * @param page
 * @param url
 * @returns {Promise<*>}
 */
async function getResourceContent(page, url) {
    const {content, base64Encoded} = await page._client.send(
        'Page.getResourceContent',
        {frameId: String(page.mainFrame()._id), url},
    );
    assert.equal(base64Encoded, true);
    return content;
};


/**
 *  将cookie 的字符串设置到页面中区
 * @param cookies_str
 * @param page
 * @param domain
 * @returns {Promise<void>}
 */
// async function addCookies(cookies_str: string, page: puppeteer.Page, domain: string){
async function addCookies(cookies_str, page, domain) {

    let cookies = cookies_str.split(';').map(pair => {
        let name = pair.trim().slice(0, pair.trim().indexOf('='))
        let value = pair.trim().slice(pair.trim().indexOf('=') + 1)
        return {name, value, domain}
    });
    await Promise.all(cookies.map(pair => {
        return page.setCookie(pair)
    }))
}

/**
 * 绕过知名网站的自动化反扒
 * @param bizArgs
 * @param page
 * @returns {Promise<void>}
 */
async function antiCrawlSettings(bizArgs, page) {
    //2.重写webdriver,绕过webdriver测试
    await page.evaluateOnNewDocument(() => {
        Object.defineProperty(navigator, 'webdriver', {
            get: () => false,
        });
    });
    //3.绕过Chrome测试
    await page.evaluateOnNewDocument(() => {
        window.navigator.chrome = {
            runtime: {},
        };
    });
    //4.绕过插件长度测试
    await page.evaluateOnNewDocument(() => {
        Object.defineProperty(navigator, 'plugins', {
            get: () => [1, 2, 3, 4, 5],
        });
    });
    //5.绕过语言测试
    await page.evaluateOnNewDocument(() => {
        Object.defineProperty(navigator, 'languages', {
            get: () => ['zh-cn', 'en', 'en-US'],
        });
    });
}

/**
 * 滚动到屏幕最底部
 * @param page
 * @returns {*}
 */
function autoScroll(page) {
    return page.evaluate(() => {
        return new Promise((resolve, reject) => {
            var totalHeight = 0;
            var distance = 100;
            var timer = setInterval(() => {
                var scrollHeight = document.body.scrollHeight;
                window.scrollBy(0, distance);
                totalHeight += distance;
                if (totalHeight >= scrollHeight) {
                    clearInterval(timer);
                    resolve();
                }
            }, 100);
        })
    });
}

/**
 * 处理当前page 页的弹窗事件
 * @param page
 * @returns {Promise<void>}
 */
async function onDialog(page) {
    await page.on('dialog', async dialog => {
        console.log(dialog.message());//打印出弹框的信息
        console.log(dialog.type());//打印出弹框的类型，是alert、confirm、prompt哪种
        console.log(dialog.defaultValue());//打印出默认的值只有prompt弹框才有
        // await page.waitFor(2000);//特意加两秒等可以看到弹框出现后取消
        await dialog.dismiss();
        // await dialog.accept('demo');accept函数也是可以的呢，可以向prompt弹框输入文字
    });
}

module.exports = {
    getBoundingClientRect,
    getResourceTree,
    getResourceContent,
    onDialog,
    addCookies,
    antiCrawlSettings,
    autoScroll,
}
